import { ConfigureService } from '@app/configure';
import { JwtVerifyService } from '@app/jwt-verify';
import { Injectable } from '@nestjs/common';
import { DbService } from 'apps/admin/src/db/db.service';
import { MemberService } from '../member/member.service';
import * as dayjs from 'dayjs';
import { CacheService } from '@app/cache';
import LoginError from './error/LoginError';

@Injectable()
export class LoginService {
    constructor(
        private readonly cache:CacheService,
        private readonly db:DbService,
        private readonly jwt:JwtVerifyService,
        private readonly config:ConfigureService,
        private readonly memberService:MemberService
    ){}

    public async login(account:string, password:string, merchantName:string, ip:string) {
        let merchantId = 0
        if(merchantName != null) {
            const merchant = await this.db.merchant.findOne({name : merchantName}, ['id', 'enable'])
            if(merchant == null) throw new LoginError('商户不存在')
            if(!merchant.enable) throw new LoginError('账号已被禁用', 301);

            merchantId = merchant.id
        }

        
        let time = dayjs().unix()
        let nextDayTime = dayjs(dayjs().format('YYYY-MM-DD')).add(1, 'day').unix() //下一天整点
        const loginFailMaxCount = Number(this.config.get<number>('loginFailMaxCount'))
        const loginCountKey = 'login.er.' + merchantId + '.' + account + '.' + dayjs().format('YYMD')

        let loginCount = Number((await this.cache.get(loginCountKey)) || 0)
        if(loginCount >= loginFailMaxCount) throw new LoginError(`当然登陆失败次数已超过${loginFailMaxCount}次`)

        let lockKey = 'login.' + merchantId + '.' + account

        const lock = await this.cache.set(lockKey, '', 10, 'NX')
        if(!lock) return null

        const member = await this.db.member.findOne({account : account, merchantId : merchantId}, ['name', 'password', 'id', 'salt', 'belong', 'canSuper', 'enable'])
        if(!member || this.memberService.buildPassword(password, member.salt) != member.password) {

            this.cache.del(lockKey)
            this.cache.set(loginCountKey, loginCount + 1, nextDayTime - time)


            throw new LoginError('账号或密码错误', 401, loginFailMaxCount - loginCount - 1);
        }

        if(!member.enable) {
            throw new LoginError('账号已被禁用', 301);
        }

        this.cache.del(lockKey)
        if(loginCount > 0) {
            this.cache.del(loginCountKey)
        }

        this.db.member.update({id : member.id}, {lastLoginTime : time, lastIp : ip})


        return {
            name : member.name,
            super : member.canSuper,
            belong : member.belong,
            ...this.makeToken(member.id, time)
        }

         
    }

    public makeToken(id:number, time?:number) {
        if(!time) {
            time = Math.floor((new Date()).getTime() / 1000)
        }

        const {secret, expire, scale} = this.config.get('jwt')



        let payload = {key : id * scale + scale, id : Math.ceil((time - 1030) / 263), time : time}
        let accessToken = this.jwt.sign(payload, {
            secret : secret,
            expiresIn : expire
        })

        

        return {
            accessToken,
            refreshToken : '1',
            expire : expire
        }
    } 
}
